package com.guangwei.example.cameratest;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.OutputConfiguration;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
import android.widget.Button;
import android.widget.Toast;

import java.util.Arrays;
import java.util.List;

import static android.hardware.camera2.CameraManager.*;

public class MainActivity extends AppCompatActivity{
    private final static String TAG = "CameraTest";

    private TextureView mTextureView;
    private Button mBtnShot;

    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHander;

    private CameraDevice mCameraDevice = null;
    private ImageReader mImageReader = null;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mPreviewRequstBuilder;
    private CaptureRequest mPreviewRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initBackgroundHander();
    }

    private void initBackgroundHander() {
        mBackgroundThread = new HandlerThread("BackgroundHandlerThread");
        mBackgroundThread.start();
        mBackgroundHander = new Handler(mBackgroundThread.getLooper());
    }

    private void initView() {
        mTextureView = findViewById(R.id.textureView);
        mBtnShot = findViewById(R.id.btn_shot);

        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }

    private final SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
            Log.i(TAG, "onSurfaceTextureAvailable: ++");
            try {
                Log.i(TAG, "onCreate: call initCamera()");
                initCamera();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
            Log.i(TAG, "onSurfaceTextureSizeChanged: ++");
        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
            Log.i(TAG, "onSurfaceTextureDestroyed: ++");
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
            Log.i(TAG, "onSurfaceTextureUpdated: ++");
        }
    };

    public void initCamera() throws CameraAccessException {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            Toast.makeText(this, "Camera permission not granted, exit!", Toast.LENGTH_LONG).show();
            return;
        } else {
            CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    Log.i(TAG, "onOpened: ++");
                    mCameraDevice = camera;
                    createPreviewSession();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    Log.i(TAG, "onDisconnected: ++");
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    Log.i(TAG, "onError: ++");
                }
            };
            Log.i(TAG, "initCamera: openCamera");
            CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
            manager.openCamera("1", stateCallback, mBackgroundHander);
        }
    }

    @SuppressLint("NewApi")
    private void createPreviewSession() {
        SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
        // should be preview size, will got it later
        surfaceTexture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());
        mImageReader = ImageReader.newInstance(mTextureView.getWidth(), mTextureView.getHeight(),
                ImageFormat.JPEG, /*maxImages*/2);

        Surface surface =new Surface(surfaceTexture);

        try {
            mPreviewRequstBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequstBuilder.addTarget(surface);

            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            Log.i(TAG, "onConfigured: ");
                            if (mCameraDevice == null) {
                                return;
                            } else {
                                mCaptureSession = session;
                            }

                            mPreviewRequest = mPreviewRequstBuilder.build();
                            try {
                                mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHander);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                            Log.i(TAG, "onConfigureFailed: ");
                        }
                    }, mBackgroundHander);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}